package com.skd.ssh.dao.base.impl;

import com.skd.ssh.dao.base.BaseDao;
import com.skd.ssh.web.query.BaseQuery;
import com.skd.ssh.web.query.PageResult;
import org.apache.commons.lang.StringUtils;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.metadata.ClassMetadata;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BaseDaoImpl<T> implements BaseDao<T> {
    @Resource(name = "hibernateTemplate")
    public HibernateTemplate hibernateTemplate;
    private final Class<T> entityClass;//具体的实现类
    private String identityName;//主键的名称

    public BaseDaoImpl() {
        //获取泛型化的父类
        ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
        //获取泛型运行期真实的类型
        this.entityClass = (Class<T>) type.getActualTypeArguments()[0];
    }

    public BaseDaoImpl(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    @PostConstruct
    public void init() {
        this.identityName = this.hibernateTemplate.getSessionFactory()
                .getClassMetadata(this.entityClass).getIdentifierPropertyName();
    }

    public void save(T t) {
        this.hibernateTemplate.save(t);
    }

    public void update(T t) {
        this.hibernateTemplate.update(t);
    }

    public void delete(Serializable id) {
        T t = get(id);
        if (t != null) {
            this.hibernateTemplate.delete(t);
        }
    }

    public T get(Serializable id) {
        return this.hibernateTemplate.get(entityClass, id);
    }

    public Long getMaxId() {
        ClassMetadata classMetadata = this.hibernateTemplate
                .getSessionFactory().getClassMetadata(entityClass);
        Long identity = (Long) this.hibernateTemplate.find("select count(" + classMetadata.getIdentifierPropertyName() + ") from " + entityClass.getName()).get(0);
        if (identity == null) {
            return 1L;
        } else {
            return identity + 1;
        }
    }

    public List query(final String hql, final Object[] params, final int start, final int limit) {
        List<Object> results = this.hibernateTemplate.execute(new HibernateCallback<List<Object>>() {
            public List<Object> doInHibernate(Session session) throws HibernateException, SQLException {

                Query query = session.createQuery(hql);

                System.out.println(hql);

                //设置查询参数
                if (params != null && params.length > 0) {
                    for (int i = 0; i < params.length; i++) {
                        query.setParameter(i, params[i]);
                    }

                }
                //设置查询返回的起始行
                if (start > 0) {
                    query.setFirstResult(start);
                }
                //设置查询返回结果的最大条数
                if (limit > 0) {
                    query.setMaxResults(limit);
                }
                return query.list();
            }
        });
        return results;
    }

    public List query(final String hql, final Object[] params) {
        return query(hql, params, -1, -1);
    }

    public List<T> queryEntity(String whereClause, Object[] params, int start, int limit) {
        StringBuffer hql = new StringBuffer("SELECT obj FROM " + entityClass.getName() + " obj WHERE 1=1 ");
        if (!whereClause.startsWith("ORDER BY")) {//如果不是以order by开始，则跟条件
            hql.append(" AND ").append(whereClause);
        } else {
            hql.append(" ").append(whereClause);//如果是以order by开始，则直接order by一个字段
        }
        return query(hql.toString(), params, start, limit);
    }

    public List<T> queryEntity(String condition, Object[] params) {
        return queryEntity(condition, params, -1, -1);
    }

    private int findCount(final BaseQuery baseQuery) {
        // select count(o) from Employee o where o.username like ? and o.email like ?
        final StringBuilder builder = new StringBuilder("select count(o) from " + entityClass.getName() + " o");
        String where = baseQuery.getWhere();
        // 有查询条件
        if (StringUtils.isNotBlank(where)) {
            builder.append(" where ").append(where);
        }
        System.out.println("PageResult findCount:" + builder.toString());

        return this.hibernateTemplate.execute(new HibernateCallback<Integer>() {
            public Integer doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(builder.toString());
                // 设置查询条件的值
                List params = baseQuery.getParams();
                int index = 0;
                for (Object object : params) {
                    query.setParameter(index++, object);
                }
                return ((Long) query.uniqueResult()).intValue();
            }
        });
    }

    public PageResult<T> findPageResult(final BaseQuery baseQuery) {

        int count = findCount(baseQuery);
        if (count == 0) {
            return new PageResult<T>();
        }

        final PageResult<T> pageResult = new PageResult<T>(baseQuery.getCurrentPage(), baseQuery.getPageSize(), count);
        // select o from Employee o where o.username like ? and o.email like ?
        final StringBuilder builder = new StringBuilder("select o from " + entityClass.getName() + " o");
        String where = baseQuery.getWhere();
        // 有查询条件
        if (StringUtils.isNotBlank(where)) {
            builder.append(" where ").append(where);
        }
        System.out.println("PageResult findPageResult:" + builder.toString());

        List<T> rows = this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {
            public List<T> doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = session.createQuery(builder.toString());
                // 设置查询条件的值
                List params = baseQuery.getParams();
                // 索引jdbc:1,hibernate:0
                // for (int i = 0; i < params.size(); i++) {
                // query.setParameter(i, params.get(i));
                // }
                int index = 0;
                for (Object object : params) {
                    query.setParameter(index++, object);
                }
                // 设置分页的信息
                // select o from Employee o limit 0,10
                // baseQuery里面的查询条件是有可能是有问题的
                // 必须使用做了错误处理后的pageResult
                int first = (pageResult.getCurrentPage() - 1) * pageResult.getPageSize();
                int max = pageResult.getPageSize();
                query.setFirstResult(first).setMaxResults(max);
                return query.list();
            }
        });
        pageResult.setRows(rows);
        return pageResult;
    }
    public Set<T> getEntrysByIds(Serializable[] ids){
        StringBuffer buffer = new StringBuffer();
        buffer.append("from "+this.entityClass.getName());
        buffer.append(" where " + this.identityName + " in(");
        for(int i=0;i<ids.length;i++){
            if(i==ids.length-1){
                buffer.append(ids[i]);
            }else{
                buffer.append(ids[i]+",");
            }
        }
        buffer.append(")");
        return new HashSet<T>((List<T>)this.hibernateTemplate.find(buffer.toString()));
    }

    public T queryEntryByProperty(final Map<String, Object> map) {
        final StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("from "+this.entityClass.getName());
        stringBuffer.append(" where 1=1");
        for(Map.Entry<String, Object> entry:map.entrySet()){
            stringBuffer.append(" and "+entry.getKey()+"=:"+entry.getKey());
        }
        return this.hibernateTemplate.execute(new HibernateCallback<T>() {
            public T doInHibernate(Session session) throws HibernateException,
                    SQLException {
                Query query = session.createQuery(stringBuffer.toString());
                for(Map.Entry<String, Object> entry:map.entrySet()){
                    query.setParameter(entry.getKey(), entry.getValue());
                }
                return (T)query.uniqueResult();
            }
        });
    }

    public List<T> queryEntrysByProperty(final Map<String, Object> map) {
        final StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("from "+this.entityClass.getName());
        stringBuffer.append(" where 1=1");
        for(Map.Entry<String, Object> entry:map.entrySet()){
            stringBuffer.append(" and "+entry.getKey()+"=:"+entry.getKey());
        }
        return this.hibernateTemplate.execute(new HibernateCallback<List<T>>() {

            public List<T> doInHibernate(Session session) throws HibernateException,
                    SQLException {
                Query query = session.createQuery(stringBuffer.toString());
                for(Map.Entry<String, Object> entry:map.entrySet()){
                    query.setParameter(entry.getKey(), entry.getValue());
                }
                return (List<T>)query.list();
            }
        });
    }
}
